// 抽象类的定义：abstract关键字,主要用于定义标准
// 抽象类的多态：多态就是父类定义一个方法不去使用或实现，让继承它的子类的使用，不同的子类使用有不同的效果或表现
abstract class Person{
  show();//抽象类里的抽象方法这样定义---继承于此的子类必须定义该抽象方法
  // 抽象类里的公共方法
  void getInfo(val){ //dart语言传递单个参数的话不可设置默认值
    if(val is int||val is String){
      print(val);
    }
  }
}

class Son extends Person{
  @override
  show() { //继承抽象类的子类必须定义父类的抽象方法，否则会报错
    // TODO: implement show
    print('子类已经继承');
  }

  run(){
    print('这是子类的独有函数');
  }
}
// 抽象类与接口类的区别在于，如果子类继承父类，如果是抽象类只强制要求必须拥有父类中所定义的抽象方法，如果是接口类则强制要求必须继承父类中的接口方法和属性
// 定义接口类
abstract class Db{ //接口类的父类内是不可写方法的，因为没地方可以调用接口父类定义的方法；
  add();
  del(); //如果父类规定的接口方法接收了参数，子类的也必须接收
  var url;
  int showInfo();
}
class Mydb implements Db{ //子类继承并遵循父类接口的规范和约定，用implements关键字; 子类必须继承父类中的所有接口属性和方法
  @override
  add(){

  }
  Mydb(this.url);//构造函数传递的形参名一定要与函数内定义的属性名一致
  @override
  del(){
    
  }
  
  @override
  var url;
  
  @override
  showInfo() {
    // url = this.url;//类传递过来的参数只能在方法内使用
    print(this.url);
    print(url);
    return 18;
  }
}

// 抽象类与接口类的应用场景：
// 抽象类：如果想要定义一个公共方法，所有子类都可以使用，又想规定子类里要拥有父类的规定的抽象方法；
// 接口类：如果只想规定子类必须拥有父类的规定的方法和属性，父类中除了规定的方法没有其他的公共方法和公共属性；
main(){
  // Person s = new Son(); //如果使子类的指针指向父类，那么子类只能使用父类里所拥有的抽象方法
  // Son s = new Son();
  // s.show();
  // s.getInfo(88);
  // s.getInfo('99');
  // Person p = new Person();//注意此处会报错，因为抽象类无法直接被实例化；

  // 实例化接口子类---注意：接口父类同样不可被实例化
  Mydb m = new Mydb(111);
  // m.url = '111';//传递参数也可以这样，但是类里面不能有构造函数接收参数
  m.showInfo();
}